<template>
	<form class="px-[35px]" @submit.prevent="onEnter">
		<input type="submit" class="hidden" />
		<base-input
			label-t="account.username"
			v-model="formValue.username"
			:name="FormFieldName.username"
			:autofocus="isPC()"
			:errorT="formRule.username.result.textT"
			:is-danger="!formRule.username.result.valid"
			@blur="checkExists('username')"
			@focus="formReset('username')" />
		<base-input
			label-t="account.emailOrMobile"
			v-model="formValue.email"
			:name="[FormFieldName.email, FormFieldName.mobile].join(',')"
			:errorT="formRule.email.result.textT"
			:is-danger="!formRule.email.result.valid"
			@blur="checkExists('email')"
			@focus="formReset('email')">
			<template #prefix-out>
				<div v-if="phoneAreaShow" class="mr-2">
					<base-select
						v-model="formValue.mobileArea"
						:options="appStore.mobileAreaOptions"
						class="w-[103px]"
						filterable
						filter-field="text"
						:popoverProps="{ placement: 'bottom-start' }"
						icon-class="!h-5" />
				</div>
			</template>
		</base-input>
		<!--		<base-input-->
		<!--			v-if="phoneAreaShow"-->
		<!--			label-t="account.mobileCode"-->
		<!--			type="number"-->
		<!--			v-model="formValue.verifyCode"-->
		<!--			:errorT="formRule.verifyCode.result.textT"-->
		<!--			:is-danger="!formRule.verifyCode.result.valid"-->
		<!--			@update:model-value="formRule.verifyCode.validator(Action.input)"-->
		<!--			@blur="formRule.verifyCode.validator(Action.blur)">-->
		<!--			<template #suffix>-->
		<!--				<base-code-phone-->
		<!--					:area-code="formValue.mobileArea"-->
		<!--					:phone-number="formValue.email"-->
		<!--					:disabled="!formRule.email.result.valid"-->
		<!--					scene="register"-->
		<!--					@send-success="formReset('verifyCode', true)" />-->
		<!--			</template>-->
		<!--		</base-input>-->
		<base-input
			label-t="account.password"
			type="password"
			v-model="formValue.password"
			:name="FormFieldName.password"
			:rules="formRule.password.result.rules"
			:is-danger="!formRule.password.result.valid"
			@blur="formRule.password.validator()"
			@focus="formReset('password')" />
		<base-input
			label-t="register.invitationCodeOptional"
			:placeholder="tInput('register.invitationCode')"
			expandable
			v-model="formValue.inviteCode"
			v-model:expanded="expandedInviteCode"
			:name="FormFieldName.inviteCode"
			click-expanded-with-label
			:errorT="formRule.inviteCode.result.textT"
			:is-danger="!formRule.inviteCode.result.valid"
			@blur="formRule.inviteCode.validator()"
			@focus="formReset('inviteCode')" />
		<div class="mt-2 mb-5 flex">
			<n-popover
				:show="!formRule.accept.result.valid"
				:animated="false"
				:placement="isPC() ? 'left' : 'bottom'"
				v-bind="NBind.Popover">
				<template #trigger>
					<n-checkbox
						v-model:checked="formValue.accept"
						class="items-start [&_.n-checkbox-box-wrapper]:h-[18px]"
						@focus="formReset('accept')">
						<div class="text-sm">
							<span>{{ $t('register.readAndAgree') }}</span>
							<base-link class="text-primary" :to="TERMS_OF_SERVICE_URL">
								{{ $t('register.termsOfUser') }}
							</base-link>
							<span>{{ $t('register.and') }}</span>
							<base-link class="text-primary" :to="PRIVACY_POLICY_URL">
								{{ $t('register.privacyPolicy') }}
							</base-link>
						</div>
					</n-checkbox>
				</template>
				<base-input-error :textT="formRule.accept.result.textT" />
			</n-popover>
		</div>
		<base-button
			type="primary"
			class="h-12"
			text-t="account.register"
			:loading="loading"
			@click="onEnter" />
	</form>
	<app-captcha ref="captchaRef" type="register" />
</template>
<script lang="ts" setup>
import { NCheckbox, NPopover } from 'naive-ui'
import { find } from 'lodash-es'
import { BaseButton, BaseInput, BaseInputError, BaseLink, BaseSelect } from '@/components/base'
import { AppCaptcha } from '@/components/app/app-captcha'
import { computed, nextTick, reactive, ref, watch, onMounted } from 'vue'
import { checkUsername } from '@/api/account'
import { DeviceType, FormFieldName } from '@/enums'
import { useAccountStore, useAppStore } from '@/store'
import { useRoute } from 'vue-router'
import {
	getItem,
	hasSpace,
	isEmail,
	isInviteCode,
	isLength,
	isPC,
	isUsername,
	parseRegexp,
	t,
	tInput
} from '@/utils'
import { useMessage } from '@/hooks/'
import { PRIVACY_POLICY_URL, TERMS_OF_SERVICE_URL } from '@/constants'
import { AccountShowType, Action } from '@/types'
import { NBind } from '@/plugins/naive-ui.ts'

export type RuleType = {
	text?: string
	textT?: string
	valid: boolean
	rules?: RuleType[]
}

const emits = defineEmits(['success'])
const route = useRoute()
const accountStore = useAccountStore()
const appStore = useAppStore()
const message = useMessage()

const captchaRef = ref(null)
const phoneAreaShow = ref(false)
const expandedInviteCode = ref(!!appStore.agent?.inviteId)

// TODO 校验模式参考naive的方式；或是抽离一个form-item组件; 以及分割复用到其他页面
const formValue = reactive({
	username: '',
	email: '',
	mobileArea: '',
	// verifyCode: '',
	password: '',
	inviteCode: appStore.agent?.inviteId ?? '',
	accept: false
})
const formRule = reactive({
	username: {
		hasInput: false,
		result: <RuleType>{ valid: true },
		validator: (action?: Action) => {
			if (action === Action.reset) return (formRule.username.result = { valid: true })
			if (action === Action.input) formRule.username.hasInput = true
			if (action === Action.blur && !formRule.username.hasInput) return
			const value = formValue.username
			let msg = ''
			if (!value) {
				msg = 'register.usernameRuleRequired'
			} else if (!isUsername(value)) {
				msg = 'register.usernameRuleChar'
			} else if (!isLength(value, action === Action.input ? 0 : 3, 16)) {
				msg = 'register.usernameRuleLength'
			} else if (!/[a-zA-Z]/.test(value)) {
				msg = 'register.usernameRuleLetter'
			}
			formRule.username.result = { textT: msg, valid: !msg }
		}
	},
	email: {
		hasInput: false,
		result: <RuleType>{ valid: true },
		validator: (action?: Action) => {
			if (action === Action.reset) return (formRule.email.result = { valid: true })
			if (action === Action.input) formRule.email.hasInput = true
			if (action === Action.blur && !formRule.email.hasInput) return
			const value = formValue.email
			let msg = ''
			if (/^\d{3,}$/.test(value)) {
				const item = find(appStore.mobileAreaOptions, { id: formValue.mobileArea })
				if (
					item &&
					!isLength(value, action === Action.input ? 0 : item.limitLength[0], item.limitLength[1])
				) {
					const regexp = parseRegexp(item.regexp)
					if (!regexp.test(value)) {
						msg = item.message
					}
				}
			} else {
				if (!value) {
					msg = 'register.emailRuleRequired'
				} else if (!isLength(value, 0, action === Action.input ? 128 : 0) && !isEmail(value)) {
					msg = 'register.emailRuleInvalid'
				}
			}
			formRule.email.result = { textT: msg, valid: !msg }
		}
	},
	// verifyCode: {
	// 	hasInput: false,
	// 	result: <RuleType>{ valid: true },
	// 	validator: (action?: Action) => {
	// 		if (action === Action.reset) return (formRule.verifyCode.result = { valid: true })
	// 		if (action === Action.input) formRule.verifyCode.hasInput = true
	// 		if (action === Action.blur && !formRule.verifyCode.hasInput) return
	// 		const value = formValue.verifyCode
	// 		let msg = ''
	// 		// TODO 这里不应该出现外部变量
	// 		if (phoneAreaShow.value) {
	// 			if (action === Action.input ? !/^\d{1,6}$/.test(value) : !isCode(value)) {
	// 				msg = 'reset.step2Title'
	// 			}
	// 		}
	// 		formRule.verifyCode.result = { textT: msg, valid: !msg }
	// 	}
	// },
	password: {
		hasInput: false,
		result: <RuleType>{ valid: true },
		validator: (action?: Action) => {
			if (action === Action.reset) return (formRule.password.result = { valid: true })
			if (action === Action.input) formRule.password.hasInput = true
			if (action === Action.blur && !formRule.password.hasInput) return
			const value = formValue.password
			const spaceValid = !!value && !hasSpace(value)
			const rules = [
				{ textT: 'register.passwordRuleLength', valid: isLength(value, 8, 24) && spaceValid },
				{ textT: 'register.passwordRuleChar', valid: /[a-zA-Z]/.test(value) },
				{ textT: 'register.passwordRuleNum', valid: /[0-9]/.test(value) }
			]
			formRule.password.result = { valid: rules.every(({ valid }) => valid), rules }
		}
	},
	inviteCode: {
		hasInput: false,
		result: <RuleType>{ valid: true },
		validator: (action?: Action) => {
			if (action === Action.reset) return (formRule.inviteCode.result = { valid: true })
			if (action === Action.input) formRule.inviteCode.hasInput = true
			if (action === Action.blur && !formRule.inviteCode.hasInput) return
			const value = formValue.inviteCode
			let msg = ''
			if (!value) {
				// 非必填
			} else if (!isLength(value, 1, 30)) {
				msg = 'register.invitationCodeRuleLength'
			} else if (!isInviteCode(value)) {
				msg = 'register.invitationCodeInvalid'
			}
			formRule.inviteCode.result = { textT: msg, valid: !msg }
		}
	},
	accept: {
		hasInput: false,
		result: <RuleType>{ valid: true },
		validator: (action?: Action) => {
			if (action === Action.reset) return (formRule.accept.result = { valid: true })
			if (action === Action.input) formRule.accept.hasInput = true
			if (action === Action.blur && !formRule.accept.hasInput) return
			const value = formValue.accept
			let msg = ''
			if (!value) {
				msg = 'register.readAndAgreeRequired'
			}
			formRule.accept.result = { textT: msg, valid: !msg }
		}
	}
})

const formReset = (field: keyof typeof formRule, withValue: boolean = false) => {
	if (withValue && formValue[field]) {
		Object.assign(formValue, { [field]: field === 'accept' ? false : '' })
	}
	nextTick(() => {
		formRule[field]?.hasInput && (formRule[field].hasInput = false)
		formRule[field]?.validator?.(Action.reset)
	})
}

// TODO 失焦存在很多场景 切换到下一个输入框,切换页面,关闭页面;
// TODO 失焦校验需要延迟,要先判断当前元素还存在时 或者 页面还存在
// TODO 注册和三方注册页面 已经提示 用户名/邮箱/手机 被占用 但是还能提交; 需要异步校验
const checkExists = async (type: keyof typeof formRule) => {
	setTimeout(async () => {
		if (accountStore.accountShow !== AccountShowType.register) return
		const value = String(formValue[type])
		formRule[type]?.validator?.(Action.submit)
		if (formRule[type].result?.valid && value) {
			if (type === 'username') {
				const { data } = await checkUsername(value)
				if (!data) {
					formRule[type].result = { valid: false, textT: 'register.usernameExists' }
				}
			} else if (type === 'email') {
				const name = phoneAreaShow.value ? formValue.mobileArea + ':' + value : value
				const { data } = await checkUsername(name)
				if (!data) {
					formRule[type].result = {
						valid: false,
						textT: phoneAreaShow.value ? 'register.mobileExists' : 'register.emailExists'
					}
				}
			}
		}
	}, 1)
}

watch([() => formValue.email, () => formValue.mobileArea], ([value]) => {
	phoneAreaShow.value = /^\d{3,}$/.test(value)
	// !phoneAreaShow.value && formReset('verifyCode', true)
	// formRule.email.validator(Action.input)
})

const submitDisabled = computed(
	() =>
		!formValue.username ||
		!formValue.email ||
		!formValue.password ||
		(phoneAreaShow.value ? !formValue.mobileArea : false) ||
		!formValue.accept ||
		Object.values(formRule).some(({ result: { valid } }) => !valid)
)

const loading = ref(false)

const onSubmit = async () => {
	const agent = appStore.agent
	const from = agent?.from || ''
	const traceId = getItem('singularDeviceId') || ''
	const marketFrom = document.referrer || location.href
	try {
		const captchaObj = await (captchaRef.value as any).getValidate()
		loading.value = true
		if (!appStore.uuid) {
			appStore.setUUID()
		}
		await accountStore.register({
			deviceType: DeviceType.pc,
			deviceId: appStore.uuid,
			username: formValue.username.trim().toLowerCase(),
			password: formValue.password.trim(),
			internationalAreaCode: phoneAreaShow.value ? formValue.mobileArea.trim() : null,
			email: phoneAreaShow.value ? null : formValue.email.trim(),
			mobile: phoneAreaShow.value ? formValue.email.trim() : null,
			// code: phoneAreaShow.value ? formValue.verifyCode.trim() : null,
			inviteCode: formValue.inviteCode.trim(),
			from,
			marketFrom,
			traceId,
			...captchaObj
		})

		message.success(t('register.success'))
		emits('success')
	} catch (err) {
		loading.value = false
		message.error(err)
	}
}

const onEnter = () => {
	if (loading.value) return
	Object.values(formRule).forEach(({ validator }) => validator(Action.submit))
	nextTick(() => {
		if (submitDisabled.value) return
		onSubmit()
	})
}
onMounted(() => {
	formValue.inviteCode = (route.query.r as string) || ''
})
</script>
